import { useVuelidate } from '@vuelidate/core';
import * as validators from '@vuelidate/validators';
import i18n from '@/i18n';
const { t } = i18n.global as any;

const locale = toRef(i18n.global, 'locale');

export default () => {
  const { createI18nMessage } = validators;
  const withI18nMessage = createI18nMessage({
    t: t.bind(i18n),
  });

  // wrap each validator.
  const required = withI18nMessage(validators.required);
  const minLength = withI18nMessage(validators.minLength, {
    withArguments: true,
  });
  const maxLength = withI18nMessage(validators.maxLength, {
    withArguments: true,
  });
  const between = withI18nMessage(validators.between, {
    withArguments: true,
  });
  const sameAs = withI18nMessage(validators.sameAs, {
    withArguments: true,
  });
  const ipAddress = withI18nMessage(validators.ipAddress);
  const macAddress = withI18nMessage(validators.macAddress);
  const numeric = withI18nMessage(validators.numeric);
  const requiredIf = withI18nMessage(validators.requiredIf, {
    withArguments: true,
  });
  const minValue = withI18nMessage(validators.minValue, {
    withArguments: true,
  });
  const maxValue = withI18nMessage(validators.maxValue, {
    withArguments: true,
  });

  const pattern = ref((pattern: any) => {
    return withI18nMessage(validators.helpers.regex(pattern), {
      messagePath: () => t('validations.pattern'),
    });
  });

  const getValidationState = (model: { $dirty: any; $error: any }) => {
    const { $dirty, $error } = model;
    return $dirty ? !$error : null;
  };

  // params: (v$, property)
  const elementInputValidator = ref(
    (v$: { [index: string]: any }, property: string) => {
      return (rule: any, value: any, callback: any) => {
        v$.value.$touch();
        if (
          getValidationState(
            property.split('.').reduce((acc, key) => acc[key], v$.value),
          )
        ) {
          callback();
        } else {
          callback(
            new Error(
              property.split('.').reduce((acc, key) => acc[key], v$.value)
                .$errors[0].$message as string,
            ),
          );
        }
        v$.value.$reset();
      };
    },
  );

  watch(locale, () => {
    elementInputValidator.value = (
      v$: { [index: string]: any },
      property: string,
    ) => {
      return (rule: any, value: any, callback: any) => {
        v$.value.$touch();
        if (getValidationState(v$.value[property])) {
          callback();
        } else {
          callback(new Error(v$.value[property].$errors[0].$message as string));
        }
        v$.value.$reset();
      };
    };
    pattern.value = (pattern: any) => {
      return withI18nMessage(validators.helpers.regex(pattern), {
        messagePath: () => t('validations.pattern'),
      });
    };
  });

  return {
    getValidationState,
    useVuelidate,
    required,
    minLength,
    maxLength,
    between,
    sameAs,
    ipAddress,
    macAddress,
    numeric,
    requiredIf,
    pattern,
    minValue,
    maxValue,
    elementInputValidator,
    withI18nMessage,
  };
};
